package com.jagochan.imchat.module.user.service.impl;

import com.jagochan.imchat.module.common.domain.enums.YesOrNoEnum;
import com.jagochan.imchat.module.common.utils.RedissonUtil;
import com.jagochan.imchat.module.common.utils.redissonlock.EnableRedissonLock;
import com.jagochan.imchat.module.user.dao.UserBackpackDao;
import com.jagochan.imchat.module.user.domain.entity.UserBackpack;
import com.jagochan.imchat.module.user.domain.enums.IdempotentEnum;
import com.jagochan.imchat.module.user.domain.enums.ItemEnum;
import com.jagochan.imchat.module.user.service.UserBackpackService;
import org.springframework.aop.framework.AopContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service
public class UserBackpackServiceImpl implements UserBackpackService {
    @Resource
    private UserBackpackDao userBackpackDao;

    @Resource
    @Lazy
    private UserBackpackServiceImpl userBackpackServiceImpl;

    /**
     * 发放物品
     *
     * @param uid            用户ID
     * @param itemId         物品ID
     * @param idempotentEnum 幂等类型（为了防止幂等唯一标识重复）
     * @param businessId     幂等唯一标识
     */
    public void requireItemOld(Long uid, Long itemId, IdempotentEnum idempotentEnum, String businessId) {
        String idempotentKey = getIdempotentKey(itemId, idempotentEnum, businessId);

        RedissonUtil.executeWithLock(idempotentKey, () -> {
            // 判断幂等是否存在
            UserBackpack userBackpack = userBackpackDao.selectByIdempotent(idempotentKey);
            if (userBackpack != null) return; // 已经存在直接返回
            // 发放物品
            UserBackpack po = UserBackpack.builder().uid(uid).itemId(itemId).idempotent(idempotentKey)
                    .status(YesOrNoEnum.NO.getStatus()).build();
            userBackpackDao.saveOrUpdate(po);
        });
    }

    @Override
    public void requireItem(Long uid, Long itemId, IdempotentEnum idempotentEnum, String businessId) {
        String idempotentKey = getIdempotentKey(itemId, idempotentEnum, businessId);
        // userBackpackServiceImpl.doRequireItem(uid, itemId, idempotentKey);
        ((UserBackpackServiceImpl) AopContext.currentProxy()).doRequireItem(uid, itemId, idempotentKey);
    }

    @EnableRedissonLock(key = "#idempotent")
    public void doRequireItem(Long uid, Long itemId, String idempotent) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        // 判断幂等是否存在
        UserBackpack userBackpack = userBackpackDao.selectByIdempotent(idempotent);
        if (userBackpack != null) return; // 已经存在直接返回
        // 发放物品
        UserBackpack po = UserBackpack.builder().uid(uid).itemId(itemId).idempotent(idempotent)
                .status(YesOrNoEnum.NO.getStatus()).build();
        userBackpackDao.saveOrUpdate(po);
    }

    private String getIdempotentKey(Long itemId, IdempotentEnum idempotentEnum, String businessId) {
        return String.format("%d(%d)%s", itemId, idempotentEnum.getType(), businessId);
    }


    ///////////////////下面的方法和CRUD有关/////////////////////////


    @Override
    public Integer countByItemId(Long uid, Integer itemId) {
        return userBackpackDao.countByItemId(uid, itemId);
    }

    /**
     * 获取uid用户的一张有效的改名卡，若无有效改名卡则返回null
     *
     * @param uid
     */
    @Override
    public UserBackpack getModifyNameCard(Long uid) {
        return userBackpackDao.selectOneByUidAndItemId(uid, ItemEnum.MODIFY_NAME_CARD.getId());
    }

    /**
     * 使用改名卡。把id为id的改名卡的status修改为1（已使用）
     *
     * @param id
     */
    @Override
    public Boolean useModifyNameCard(Long id) {
        return userBackpackDao.useModifyNameCard(id);
    }

    /**
     * 查询当前用户拥有的【物品】
     */
    @Override
    public List<UserBackpack> listByUidAndItemIds(Long uid, List<Long> itemIdList) {
        return userBackpackDao.selectByUidAndItemIds(uid, itemIdList);
    }

    @Override
    public UserBackpack getValidByUidAndItemId(Long uid, Long itemId) {
        return userBackpackDao.selectOneByUidAndItemId(uid, itemId);
    }
}
